package crypto;

import gnu.crypto.sig.ISignature;
import gnu.crypto.sig.ISignatureCodec;
import gnu.crypto.sig.SignatureFactory;
import gnu.crypto.sig.dss.DSSSignatureRawCodec;

import java.io.IOException;
import java.io.InputStream;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.util.HashMap;
import java.util.Map;

/**
 * Clase que hace firmas digitales
 */
public class SignatureManager
{
	public final static String RUTA_PRIV = "./data/DSAPrivate.key";
	
	public final static String RUTA_PUB = "./data/DSAPublic.key";
	
	/**
	 * Firma los datos que son pasados por parametro con la llave privada
	 * 
	 * @param datos los datos a firmar
	 * @param rutaLlave la ruta de la llave privada con la que se van a firmar los datos
	 * @return un arreglo de bytes con la firma digital
	 * 
	 * @throws IOException si la ruta de la llave es incorrecta
	 */
	@SuppressWarnings({ "unchecked", "rawtypes" })
	public static byte[] firmar(byte[] datos, String rutaLlave) throws IOException
	{
		ISignature dss = SignatureFactory.getInstance("DSS");
		Map atrib = new HashMap();

		PrivateKey key = KeyUtils.loadDSAPrivateKey(RUTA_PRIV);
		atrib.put(ISignature.SIGNER_KEY, key);
		dss.setupSign(atrib);

		dss.update(datos, 0, datos.length);
		Object sig = dss.sign();

		ISignatureCodec codec = new DSSSignatureRawCodec();
		return codec.encodeSignature(sig);

	}

	/**
	 * Verifica una firma digital con la llave publica y los datos originales
	 * 
	 * @param datos los datos originales de la firma
	 * @param firma la firma digital a verificar
	 * @param key la llave publica para verificar
	 * 
	 * @return true si la firma es correcta false de lo contrario
	 * 
	 * @throws IOException si la ruta de la llave es incorrecta
	 */
	@SuppressWarnings({ "rawtypes", "unchecked" })
	public static boolean verificarFirma(byte[] datos, byte[] firma, InputStream key) throws IOException
	{
		ISignature dss = SignatureFactory.getInstance("DSA");
		Map atrib = new HashMap();
		
		PublicKey pubKey = KeyUtils.loadDSAPublicKey(key);
		
		atrib.put(ISignature.VERIFIER_KEY, pubKey);
		dss.setupVerify(atrib);
		
		dss.update(datos, 0, datos.length);
		
		ISignatureCodec codec = new DSSSignatureRawCodec();
	    Object sig = codec.decodeSignature(firma);
		
		return dss.verify(sig);
	}
}
